// 螺旋数字矩阵
// 题目链接：https://fcqian.blog.csdn.net/article/details/135085069
// 做题思路：
// 让机器按照一个固定的路径行走，一旦到了矩阵边界和已经标记过的格子就右转，如此往复直到终点
// 矩阵一开始所有值都是*
// 这题按照正规逻辑很难，比如，求9位于矩阵的哪个格子？这个我感觉不好算
// 此外，DFS和BFS好像也不适用
// 但解题的模板是可以和二维矩阵BFS遍历差不多的

const zddTool = require('../commonTool/zddtool.js');

class ClockwiseSpiralMatrix {
    /**
     *
     * @param {Number} maxNum 矩阵最大值
     * @param {Number} lines 行数
     */
    constructor(maxNum, lines) {
        let cols = Math.ceil(maxNum / lines);
        this.info = {
            rows: lines,
            cols,
            maxNum,
        };

        this.matrix = zddTool.new2DMatrix(this.info.rows, this.info.cols, '*');
        this.init();
        this.print();
    }

    /**
     * 顺时针 右下左上
     */
    static directions = [
        [0, 1], // 右
        [1, 0], // 下
        [0, -1], // 左
        [-1, 0], // 上
    ];

    /**
     * 以BFS的方式轮询整个矩阵，返回矩阵中的每一个节点
     * @returns
     */
    init() {
        console.log(`ClockwiseSpiralMatrix print`);
        let { info } = this; // 提取矩阵中的矩阵行数，列数等信息
        let allVisited = new Array(info.rows * info.cols).fill(false); // 所有节点是否被访问 -> 如果已经被访问，那需要转向
        let currentDirection = 0;
        let startX = 0;
        let startY = 0;

        this.matrix[startX][startY] = 1;
        allVisited[0] = true;
        for (let i = 1; i < info.maxNum; i++) {
            // 判断是否要转向
            let newX =
                startX + ClockwiseSpiralMatrix.directions[currentDirection][0];
            let newY =
                startY + ClockwiseSpiralMatrix.directions[currentDirection][1];

            if (
                newX >= info.rows ||
                newX < 0 ||
                newY < 0 ||
                newY >= info.cols ||
                allVisited[newX * info.cols + newY] == true
            ) {
                currentDirection = (currentDirection + 1) % 4;
                newX =
                    startX +
                    ClockwiseSpiralMatrix.directions[currentDirection][0];
                newY =
                    startY +
                    ClockwiseSpiralMatrix.directions[currentDirection][1];
            }

            startX = newX;
            startY = newY;

            this.matrix[startX][startY] = i + 1;
            allVisited[startX * info.cols + startY] = true;
        }
    }

    /**
     * 通过console.log绘制矩阵
     */
    print(visitArray) {
        /**
         * -------------
         * | 1 | 2 | 3 |
         * | 4 |[5]| 6 |
         * | 7 | 8 | 9 |
         * -------------
         */
        // 获取所有元素的字符串最大长度

        let maxNumLen = 3; // 默认值是3
        const { info } = this;

        this.matrix.forEach((row) => {
            row.forEach((ele) => {
                if (ele.length > maxNumLen) {
                    maxNumLen = ele.length;
                }
            });
        });

        const eleWidth = maxNumLen + 2;

        const strBorder = new Array(eleWidth * info.cols)
            .fill('-')
            .join()
            .replace(/,/g, '');

        console.log(`${strBorder}`);
        this.matrix.forEach((row, _rIdx) => {
            let strRow = '|';
            row.forEach((ele, _cIdx) => {
                let strEle = `${ele}`;
                if (
                    visitArray != null &&
                    visitArray[_rIdx * info.cols + _cIdx] === true
                ) {
                    strEle = `[${strEle}]`;
                }

                while (strEle.length < eleWidth) {
                    strEle = ` ${strEle} `;
                }
                strEle = strEle.slice(0, eleWidth);
                strRow += `${strEle}|`;
            });
            console.log(`${strRow}`);
        });
        console.log(`${strBorder}`);
    }
}

// test
console.log(`[ClockwiseSpiralMatrix]: start`);
new ClockwiseSpiralMatrix(9, 4);
new ClockwiseSpiralMatrix(3, 5);
new ClockwiseSpiralMatrix(120, 7);
